package engine.systems.timeline.timeline
{
	import ash.core.Entity;
	
	import engine.classes.enumerations.SystemPriority;
	import engine.systems.update.GameSystem;
	
	public class TimelineSystem extends GameSystem
	{
		public function TimelineSystem()
		{
			super(TimelineNode, updateNode);
			
			this.priority = SystemPriority.TIMELINE;
		}
		
		private function updateNode(node:TimelineNode, time:Number):void
		{
			var timeline:Timeline = node.timeline;
			
			if(timeline.locked) return;
			if(timeline._data.length == 0)
			{
				trace("No Timeline FrameData... yet.");
				return;
			}
		
			var frameEvent:FrameEvent;
			
			frameEvent = timeline._manualFrameEvent;
			if(frameEvent)
			{
				trace(frameEvent.action, frameEvent.frame);
				if(this.canAdvanceFrame(timeline, time, node.entity))
				{
					this.advanceFrameWithFrameEvent(timeline, frameEvent);
					timeline._manualFrameEvent = null;
				}
			}
			else if(timeline._playing)
			{
				if(this.canAdvanceFrame(timeline, time, node.entity))
				{
					frameEvent = timeline.data[timeline._frame - 1].event;
					if(frameEvent)
					{
						this.advanceFrameWithFrameEvent(timeline, frameEvent);
					}
					else
					{
						this.advanceFrame(timeline);
					}
				}
			}
		}
		
		private function canAdvanceFrame(timeline:Timeline, time:Number, entity:Entity):Boolean
		{
			timeline._time += time;
			if(timeline._time >= timeline.frameRate)
			{
				timeline._time -= timeline.frameRate;
				
				if(timeline._time > timeline.frameRate)
				{
					trace("Timeline System :: updateNode() :: Entity <" + entity.name + ">'s frameRate is too fast!");
				}
				
				return true;
			}
			
			return false;
		}
		
		private function advanceFrameWithFrameEvent(timeline:Timeline, frameEvent:FrameEvent):void
		{
			switch(frameEvent.action)
			{
				case Timeline.PLAY:
					timeline._playing = true;
					this.advanceFrame(timeline);
					break;
				
				case Timeline.STOP:
					timeline._playing = false;
					timeline._time = 0;
					break;
				
				case Timeline.GOTO_AND_PLAY:
					timeline._playing = true;
					this.gotoFrame(timeline, frameEvent.frame);
					break;
				
				case Timeline.GOTO_AND_STOP:
					timeline._playing = false;
					timeline._time = 0;
					this.gotoFrame(timeline, frameEvent.frame);
					break;
			}
		}
		
		private function advanceFrame(timeline:Timeline):void
		{
			var frame:int = timeline._frame;
			timeline.forward ? frame++ : frame--;
			
			this.gotoFrame(timeline, frame);
		}
		
		private final function gotoFrame(timeline:Timeline, frame:*):void
		{
			var validFrame:Boolean = false;
			
			if(frame is Number)
			{
				if(frame > timeline._data.length) frame = 1;
				else if(frame < 1) frame = timeline._data.length;
				
				timeline._frame = frame;
				validFrame = true;
			}
			else if(frame is String)
			{
				for(var i:int = 0; i < timeline._data.length; i++)
				{
					if(timeline.data[i].label == frame)
					{
						timeline._frame = i + 1;
						validFrame = true;
						break;
					}
				}
			}
			
			if(validFrame) this.handleLabels(timeline);
			else
			{
				trace("Invalid gotoFrame!");
			}
		}
		
		private function handleLabels(timeline:Timeline):void
		{
			var label:String = timeline._data[timeline._frame - 1].label;
			if(label)
			{
				for(var i:int = 0; i < timeline._labelHandlers.length; i++)
				{
					var handler:LabelHandler = timeline._labelHandlers[i];
					if(handler.label == label)
					{
						handler.handler.call();
						if(handler.once)
						{
							handler.destroy();
							timeline._labelHandlers.splice(i, 1);
							i--;
						}
					}
				}
			}
		}
	}
}